package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.BusinessException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUserCommonConfig;
import org.dromara.system.domain.SysUserLotteryConfig;
import org.dromara.system.domain.SysUserLotteryRecords;
import org.dromara.system.domain.SysUserPurse;
import org.dromara.system.domain.bo.SysUserLotteryRecordsBo;
import org.dromara.system.domain.bo.SysUserPurseBo;
import org.dromara.system.domain.vo.PrizeDrawVo;
import org.dromara.system.domain.vo.QueryLotteryInfoVo;
import org.dromara.system.domain.vo.SysUserLotteryRecordsVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.enums.SysUserPointsRecordsEnum;
import org.dromara.system.mapper.SysUserLotteryRecordsMapper;
import org.dromara.system.service.*;
import org.dromara.system.service.impl.permission.PermissionBaseService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * 抽奖记录Service业务层处理
 *
 * @author Lion Li
 * @date 2025-07-29
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserLotteryRecordsServiceImpl extends ServiceImpl<SysUserLotteryRecordsMapper, SysUserLotteryRecords> implements ISysUserLotteryRecordsService {


    private final PermissionBaseService permissionBaseService;
    private final ISysUserService sysUserService;
    private final ISysUserCommonConfigService sysUserCommonConfigService;
    private final ISysUserLotteryConfigService sysUserLotteryConfigService;
    private final ISysUserPointsRecordsService sysUserPointsRecordsService;
    private final ISysUserLotteryPointsRecordsService sysUserLotteryPointsRecordsService;
    private final ISysUserPurseService sysUserPurseService;

    /**
     * 查询抽奖记录
     *
     * @param id 主键
     * @return 抽奖记录
     */
    @Override
    public SysUserLotteryRecordsVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询抽奖记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 抽奖记录分页列表
     */
    @Override
    public TableDataInfo<SysUserLotteryRecordsVo> queryPageList(SysUserLotteryRecordsBo bo, PageQuery pageQuery) {
        permissionBaseService.assignPermission(bo);
        IPage<SysUserLotteryRecordsVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SysUserLotteryRecordsVo> list = baseMapper.findAll(page, bo);
        return TableDataInfo.build(list);
    }

    @Override
    public TableDataInfo<SysUserLotteryRecordsVo> listReception(SysUserLotteryRecordsBo bo, PageQuery pageQuery) {
        permissionBaseService.aloneAssignPermission(bo);
        IPage<SysUserLotteryRecordsVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SysUserLotteryRecordsVo> list = baseMapper.findAll(page, bo);
        return TableDataInfo.build(list);
    }


    /**
     * 查询符合条件的抽奖记录列表
     *
     * @param bo 查询条件
     * @return 抽奖记录列表
     */
    @Override
    public List<SysUserLotteryRecordsVo> queryList(SysUserLotteryRecordsBo bo) {
        LambdaQueryWrapper<SysUserLotteryRecords> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysUserLotteryRecords> buildQueryWrapper(SysUserLotteryRecordsBo bo) {
        LambdaQueryWrapper<SysUserLotteryRecords> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SysUserLotteryRecords::getId);
        lqw.eq(bo.getUserId() != null, SysUserLotteryRecords::getUserId, bo.getUserId());
        lqw.eq(bo.getPoints() != null, SysUserLotteryRecords::getPoints, bo.getPoints());
        lqw.eq(bo.getRewards() != null, SysUserLotteryRecords::getRewards, bo.getRewards());
        return lqw;
    }

    /**
     * 新增抽奖记录
     *
     * @param bo 抽奖记录
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SysUserLotteryRecordsBo bo) {
        SysUserLotteryRecords add = MapstructUtils.convert(bo, SysUserLotteryRecords.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改抽奖记录
     *
     * @param bo 抽奖记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SysUserLotteryRecordsBo bo) {
        SysUserLotteryRecords update = MapstructUtils.convert(bo, SysUserLotteryRecords.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysUserLotteryRecords entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除抽奖记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PrizeDrawVo prizeDraw() {
        Long userId = LoginHelper.getUserId();
        SysUserPurse sysUserPurse = sysUserPurseService.lambdaQuery().eq(SysUserPurse::getUserId, userId).one();
        BigDecimal lotteryPoints = sysUserPurse.getLotteryPoints();
        SysUserVo sysUserVo = sysUserService.selectUserById(userId);
        BusinessException.isTrue(NumberUtil.isLess(lotteryPoints, BigDecimal.ONE), "抽奖积分余额不足！");

        //查询抽奖相关配置
        SysUserCommonConfig sysUserCommonConfig = sysUserCommonConfigService.lambdaQuery().eq(SysUserCommonConfig::getUserId, sysUserVo.getOneId()).one();
        BigDecimal lotteryMinimumGuaranteeReward = sysUserCommonConfig.getLotteryMinimumGuaranteeReward();
        BusinessException.isTrue(NumberUtil.isLessOrEqual(lotteryMinimumGuaranteeReward, BigDecimal.ZERO), "请设置正确的保底金额！");

        List<SysUserLotteryConfig> list = sysUserLotteryConfigService.lambdaQuery().eq(SysUserLotteryConfig::getUserId, sysUserVo.getOneId()).list();
        BusinessException.isTrue(CollUtil.isEmpty(list), "奖池金额未配置！");

        Integer monthLotteryNum = sysUserCommonConfig.getMonthLotteryNum();
        //查询本月抽奖次数
        Long count = lambdaQuery()
            .eq(SysUserLotteryRecords::getUserId, userId)
            .ge(SysUserLotteryRecords::getCreateTime, DateUtil.beginOfMonth(DateUtil.date()))
            .le(SysUserLotteryRecords::getCreateTime, DateUtil.endOfMonth(DateUtil.date())).count();
        BusinessException.isTrue(count >= Convert.toLong(monthLotteryNum), "单月最多抽奖次数为" + monthLotteryNum + "次！");

        //奖池抽奖步数+1
        int userLotteryStep = sysUserCommonConfig.getLotteryStep() + 1;
        BigDecimal rewards = BigDecimal.ZERO;
        int finalUserLotteryStep = userLotteryStep;
        SysUserLotteryConfig sysUserLotteryConfig = list.stream().filter(t -> ObjectUtil.equal(t.getStep(), finalUserLotteryStep)).findFirst().orElse(null);
        //没有就中保底金额
        if (ObjectUtil.isNull(sysUserLotteryConfig)) {
            rewards = lotteryMinimumGuaranteeReward;
        } else {
            rewards = sysUserLotteryConfig.getRewards();
        }
        //增加抽奖记录
        SysUserLotteryRecordsBo sysUserLotteryRecordsBo = SysUserLotteryRecordsBo.builder()
            .userId(userId)
            .points(NumberUtil.mul(BigDecimal.ONE, -1))
            .rewards(rewards)
            .build();
        insertByBo(sysUserLotteryRecordsBo);

        //钱包变更  抽奖积分减少  积分增加
        SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
            .userId(userId)
            .type(SysUserPointsRecordsEnum.LOTTERY_REWARDS_POINTS.getCode())
            .points(rewards)
            .build();
        sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));

        SysUserPurseBo sysUserLotteryPurseBo = SysUserPurseBo.builder()
            .userId(userId)
            .lotteryPoints(NumberUtil.mul(BigDecimal.ONE, -1))
            .build();
        sysUserLotteryPointsRecordsService.updateUserLotteryPoints(CollUtil.newArrayList(sysUserLotteryPurseBo));
        //奖池步数变更
        Optional<SysUserLotteryConfig> maxStep = list.stream()
            .max(Comparator.comparingInt(SysUserLotteryConfig::getStep));
        SysUserLotteryConfig maxLotteryConfig = maxStep.get();
        if (ObjectUtil.equal(userLotteryStep, maxLotteryConfig.getStep())) {
            userLotteryStep = 0;
        }
        //修改抽奖步数
        sysUserCommonConfigService.lambdaUpdate()
            .set(SysUserCommonConfig::getLotteryStep, userLotteryStep)
            .eq(SysUserCommonConfig::getId, sysUserCommonConfig.getId())
            .update();
        return PrizeDrawVo.builder().rewards(rewards).build();
    }

    @Override
    public QueryLotteryInfoVo queryLotteryInfo() {
        Long userId = LoginHelper.getUserId();
        SysUserPurse sysUserPurse = sysUserPurseService.lambdaQuery().eq(SysUserPurse::getUserId, userId).one();
        BigDecimal lotteryPoints = sysUserPurse.getLotteryPoints();
        return QueryLotteryInfoVo
            .builder()
            .prizeDrawPoints(BigDecimal.ONE)
            .lotteryPoints(lotteryPoints).build();
    }
}
